import { defineStore } from 'pinia';
import { api, IResponse } from 'src/boot/axios';
import { plainToInstance } from 'class-transformer';
import { LocalStorage } from 'quasar';
import Me, { NotificationSettings } from 'src/models/Me';
import { signOut } from 'src/utils/auth';
import LanguageConfig from 'src/models/LanguageConfig';
import User from 'src/models/User';
import Video from 'src/models/Video';
import Audio from 'src/models/Audio';
import Playlist from 'src/models/Playlist';
import { IPage } from 'boot/axios';
import Message from 'src/models/Message';
import SocialLink from 'src/models/SocialLink';
import PinnedItem from 'src/models/PinnedItem';
import { useGlobalStore } from 'stores/global-store';
import { singularSdk } from 'singular-sdk';

export interface signinParams {
  email: string;
  password: string;
}
export interface signupParams {
  username: string;
  email: string;
  password: string;
  birthday: number;
}
export interface pinParms {
  type: string;
  id: string;
  image?: string;
}

export interface UserStateInterface {
  currentUser: Me | null;
  targetUser?: User;
  token: string;
  shortcuts: Array<PinnedItem>;
  languages: string[];
  myVideos: Video[];
  myVideosPage: IPage | null;
  myAudios: Audio[];
  myAudiosPage: IPage | null;
  myPlaylists: Playlist[];
  myPlaylistsPage: IPage | null;
  myLiked: Video[];
  myLikedPage: IPage | null;
  myHistory: Video[];
  myHistoryPage: IPage | null;
  myFollowing: User[];
  myFollowingPage: IPage | null;
  myFollowers: User[];
  myFollowersPage: IPage | null;
  watchLater: Video[];
  watchLaterPage: IPage | null;
  isDesktopNotificationEnabled: boolean;
  isNewVideoNotificationEnabled: boolean;
  isNewAudioNotificationEnabled: boolean;
  isNewFollowersNotificationEnabled: boolean;
  isComplimentNotificationEnabled: boolean;
  isReactionNotificationEnabled: boolean;
  socialLinks: SocialLink[];
  messages: Message[];
}
export const useUserStore = defineStore('user', {
  state: (): UserStateInterface => ({
    currentUser: null,
    token: '',
    shortcuts: [],
    languages: [],
    socialLinks: [],
    isDesktopNotificationEnabled: false,
    isNewVideoNotificationEnabled: false,
    isNewAudioNotificationEnabled: false,
    isNewFollowersNotificationEnabled: false,
    isComplimentNotificationEnabled: false,
    isReactionNotificationEnabled: false,
    messages: [],
    myVideos: [],
    myVideosPage: null,
    myAudios: [],
    myAudiosPage: null,
    myPlaylists: [],
    myPlaylistsPage: null,
    myLiked: [],
    myLikedPage: null,
    myHistory: [],
    myHistoryPage: null,
    myFollowing: [],
    myFollowingPage: null,
    myFollowers: [],
    myFollowersPage: null,
    watchLater: [],
    watchLaterPage: null,
  }),
  getters: {
    mySelectedLanguage: ({ currentUser }) => {
      const globalStore = useGlobalStore();
      const langs: LanguageConfig[] = [];
      if (currentUser) {
        if (currentUser.languages.length > 0) {
          currentUser.languages.forEach((code) => {
            langs.push(
              globalStore.languageConfig.filter((lang) => lang.code === code)[0]
            );
          });
        }
      }
      return langs;
    },
    selectedLanguage: ({ languages }) => {
      const globalStore = useGlobalStore();
      const langs: LanguageConfig[] = [];
      if (languages.length > 0) {
        languages.forEach((code) => {
          langs.push(
            globalStore.languageConfig.filter((lang) => lang.code === code)[0]
          );
        });
      }
      return langs;
    },
  },
  actions: {
    setCurrentUser(user: Me) {
      this.currentUser = plainToInstance(Me, user);
      singularSdk.login(this.currentUser.id);
    },
    setTargetUserInfo(user: User) {
      this.targetUser = plainToInstance(User, user);
    },
    setToken(token: string) {
      this.token = token;
      LocalStorage.set('token', token);
    },
    setShortcuts(shortcuts: any[]) {
      this.shortcuts = plainToInstance(PinnedItem, shortcuts);
    },
    setMeSelectedLanguage(langs: string[]) {
      if (this.currentUser) {
        this.currentUser.languages = langs;
      }
    },
    setSelectedLanguage(langs: string[]) {
      this.languages = langs;
    },
    setWatchLater(videos: Video[]) {
      if (videos.length > 0) {
        this.watchLater = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setWatchLaterPage(page: IPage) {
      this.watchLaterPage = page;
    },
    setMyHistory(videos: Video[]) {
      if (videos.length > 0) {
        this.myHistory = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setMyHistoryPage(page: IPage) {
      this.myHistoryPage = page;
    },
    setMyVideos(videos: Video[]) {
      if (videos.length > 0) {
        this.myVideos = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setMyVideosPage(page: IPage) {
      this.myVideosPage = page;
    },
    setMyAudios(audios: Audio[]) {
      if (audios.length > 0) {
        this.myAudios = audios.map((audios) => {
          return plainToInstance(Audio, audios);
        });
      }
    },
    setMyAudiosPage(page: IPage) {
      this.myAudiosPage = page;
    },
    setMyLiked(videos: Video[]) {
      if (videos.length > 0) {
        this.myLiked = videos.map((video) => {
          return plainToInstance(Video, video);
        });
      }
    },
    setMyLikedPage(page: IPage) {
      this.myLikedPage = page;
    },
    setMyPlaylists(playlists: Playlist[]) {
      if (playlists.length > 0) {
        this.myPlaylists = playlists.map((playlist) => {
          return plainToInstance(Playlist, playlist);
        });
      }
    },
    setMyPlaylistsPage(page: IPage) {
      this.myPlaylistsPage = page;
    },
    setMyFollowing(users: User[]) {
      if (users.length > 0) {
        this.myFollowing = users.map((user) => {
          return plainToInstance(User, user);
        });
      }
    },
    setMyFollowingPage(page: IPage) {
      this.myFollowingPage = page;
    },
    setMyFollowers(users: User[]) {
      if (users.length > 0) {
        this.myFollowers = users.map((user) => {
          return plainToInstance(User, user);
        });
      }
    },
    setMyFollowersPage(page: IPage) {
      this.myFollowersPage = page;
    },
    async initCurrentUser() {
      if (LocalStorage.has('token')) {
        const token = LocalStorage.getItem('token');
        if (token) {
          this.setToken(token as string);
          const { code, data, msg } = await api.get<any, IResponse<Me>>('/me');
          if (code === 200) {
            this.setCurrentUser(data);
          } else {
            LocalStorage.remove('token');
            throw new Error(msg);
          }
        } else {
          LocalStorage.remove('token');
        }
      }
    },
    async getUserInfo(userId: string) {
      const { code, data, msg } = await api.get<any, IResponse<User>>(
        `/user?id=${userId}`
      );
      if (code === 200) {
        this.setTargetUserInfo(data);
      } else {
        throw new Error(msg);
      }
    },
    signup(params: signupParams) {
      return new Promise((resolve, reject) => {
        api
          .post<any, IResponse<Me>>('/signup', params)
          .then((data) => {
            if (data.code === 200) {
              this.setCurrentUser(data.data);
              this.setToken(data.data.token);
              resolve(data.data);
            } else {
              reject(new Error(data.msg));
            }
          })
          .catch((error) => {
            reject(error);
          });
      });
    },
    async signin(params: signinParams) {
      return await api
        .post<any, IResponse<Me>>('/signin', params)
        .then((data) => {
          if (data.code === 200) {
            this.setCurrentUser(data.data);
            this.setToken(data.data.token);
          } else {
            throw new Error(data.msg);
          }
        });
    },
    async signinWithEmail(email: string) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/email-signin',
        { email: email }
      );
      if (code === 200) {
        this.setCurrentUser(data);
        this.setToken(data.token);
      } else {
        throw new Error(msg);
      }
    },
    async signupWithGoogle(params: {
      email: string;
      username: string;
      avatar: string;
      googleId: string;
    }) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/google-signup',
        params
      );
      if (code === 200) {
        this.setCurrentUser(data);
        this.setToken(data.token);
      } else {
        throw new Error(msg);
      }
    },
    async signupWithMslive(params: {
      email: string;
      username: string;
      avatar: string;
      msliveId: string;
    }) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/mslive-signup',
        params
      );
      if (code === 200) {
        this.setCurrentUser(data);
        this.setToken(data.token);
      } else {
        throw new Error(msg);
      }
    },
    async signupWithFacebook(params: {
      email: string;
      username: string;
      avatar: string;
      facebookId: string;
    }) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/facebook-signup',
        params
      );
      if (code === 200) {
        this.setCurrentUser(data);
        this.setToken(data.token);
      } else {
        throw new Error(msg);
      }
    },
    async signupWithTwitter(params: {
      email: string;
      username: string;
      avatar: string;
      twitterId: string;
    }) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/twitter-signup',
        params
      );
      if (code === 200) {
        this.setCurrentUser(data);
        this.setToken(data.token);
      } else {
        throw new Error(msg);
      }
    },
    async signout() {
      await signOut();
      LocalStorage.remove('token');
      this.currentUser = null;
      singularSdk.logout();
      return await api.post('/logout', null);
    },
    async pin(params: pinParms) {
      return await api
        .post<any, IResponse<any>>('/pin', params)
        .then((data) => {
          if (data.code === 200) {
            this.setShortcuts(data.data);
          } else {
            throw new Error(data.msg);
          }
        });
    },
    async getShortcuts() {
      const data = await api.get<any, IResponse<any>>('/shortcuts');
      if (data.code === 200) {
        this.setShortcuts(data.data);
      } else {
        throw new Error(data.msg);
      }
    },
    setLanguage(params: string[]) {
      return new Promise((resolve, reject) => {
        api
          .post<any, IResponse<Me>>('/my/languages', params)
          .then((data) => {
            if (data.code === 200) {
              this.setCurrentUser(data.data);
              resolve(data.data);
            } else {
              reject(new Error(data.msg));
            }
          })
          .catch((error) => reject(error));
      });
    },
    async getMyVideos(params?: any) {
      console.log(params);
      const { data, page, code, msg } = await api.post<any, IResponse<Video[]>>(
        '/my/videos',
        params
      );
      if (code === 200) {
        if (data.length > 0) {
          this.myVideos = data.map((video) => {
            return plainToInstance(Video, video);
          });
          console.log(this.myVideos);
          if (page) {
            this.myVideosPage = page;
          }
        }
      } else {
        throw new Error(msg);
      }
    },
    async getMyAudios(params?: any) {
      const data = await api.post<any, any>('/my/audios', params);
      if (data.code === 200) {
        this.setMyAudios(data.data);
        this.setMyAudiosPage(data.page);
      } else {
        throw new Error(data.msg);
      }
    },
    async getWatchLater(params?: any) {
      const { code, data, msg, page } = await api.post<any, any>(
        '/my/watchlater',
        params
      );
      if (code === 200) {
        this.setWatchLater(data);
        this.setWatchLaterPage(page);
      } else {
        throw new Error(msg);
      }
    },
    async getMyPlaylists(params?: any) {
      const data = await api.post<any, any>('/my/playlists', params);
      if (data.code === 200) {
        this.setMyPlaylists(data.data);
        this.setMyPlaylistsPage(data.page);
      } else {
        throw new Error(data.msg);
      }
    },
    async createPlaylist(title: string) {
      const { code, data, msg } = await api.post<any, IResponse<Playlist[]>>(
        '/playlist/new',
        { title: title }
      );
      if (code === 200) {
        this.setMyPlaylists(data);
      } else {
        throw new Error(msg);
      }
    },
    async getMyLiked(params: any) {
      const data = await api.post<any, any>('/my/liked', params);
      if (data.code === 200) {
        this.setMyLikedPage(data.page);
        this.setMyLiked(data.data);
      } else {
        throw new Error(data.msg);
      }
    },
    async getMyHistory(params: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<Video[]>>(
        '/my/history',
        params
      );
      if (code === 200) {
        this.setMyHistory(data);
        this.setMyHistoryPage(page ? page : {});
      } else {
        throw new Error(msg);
      }
    },
    async getMyFollowing(params: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<User[]>>(
        '/my/following',
        params
      );
      if (code === 200) {
        this.setMyFollowing(data);
        this.setMyFollowingPage(page ? page : {});
      } else {
        throw new Error(msg);
      }
    },
    async getMyFollowers(params: { page: number; size: number }) {
      const { code, data, msg, page } = await api.post<any, IResponse<User[]>>(
        '/my/followers',
        params
      );
      if (code === 200) {
        this.setMyFollowers(data);
        this.setMyFollowersPage(page ? page : {});
      } else {
        throw new Error(msg);
      }
    },
    async getUserNotificationSettings() {
      const { code, data, msg } = await api.get<
        any,
        IResponse<NotificationSettings>
      >('/my/notificationSetting');
      if (code === 200) {
        const props = Object.keys(data);
        props.forEach((key) => {
          switch (key) {
            case 'desktop':
              {
                this.isDesktopNotificationEnabled = data.desktop;
              }
              break;
            case 'newVideos':
              {
                this.isNewVideoNotificationEnabled = data.newVideos;
              }
              break;
            case 'newAudios':
              {
                this.isNewAudioNotificationEnabled = data.newAudios;
              }
              break;
            case 'newFollowers':
              {
                this.isNewFollowersNotificationEnabled = data.newFollowers;
              }
              break;
            case 'compliments':
              {
                this.isComplimentNotificationEnabled = data.compliments;
              }
              break;
            case 'reactions':
              {
                this.isReactionNotificationEnabled = data.reactions;
              }
              break;
          }
        });
      } else {
        throw new Error(msg);
      }
    },
    async updateUserNotificationSettings(settings: any) {
      console.log('updateUserNotificationSettings', settings);
      const { code, data, msg } = await api.post<
        any,
        IResponse<NotificationSettings>
      >('/my/updateNotificationSettings', settings);
      if (code === 200) {
        const props = Object.keys(data);
        props.forEach((key) => {
          switch (key) {
            case 'desktop':
              {
                this.isDesktopNotificationEnabled = data.desktop;
              }
              break;
            case 'newVideos':
              {
                this.isNewVideoNotificationEnabled = data.newVideos;
              }
              break;
            case 'newAudios':
              {
                this.isNewAudioNotificationEnabled = data.newAudios;
              }
              break;
            case 'newFollowers':
              {
                this.isNewFollowersNotificationEnabled = data.newFollowers;
              }
              break;
            case 'compliments':
              {
                this.isComplimentNotificationEnabled = data.compliments;
              }
              break;
            case 'reactions':
              {
                this.isReactionNotificationEnabled = data.reactions;
              }
              break;
          }
        });
      } else {
        throw new Error(msg);
      }
    },
    async getMySocialLinks() {
      const { code, data, msg } = await api.get<any, IResponse<SocialLink[]>>(
        '/my/sociallinks'
      );
      if (code === 200) {
        this.socialLinks = plainToInstance(SocialLink, data);
      } else {
        throw new Error(msg);
      }
    },
    async addSocialLink(param: any) {
      const { code, data, msg } = await api.post<any, IResponse<SocialLink[]>>(
        '/my/sociallinks',
        param
      );
      if (code === 200) {
        this.socialLinks = plainToInstance(SocialLink, data);
      } else {
        throw new Error(msg);
      }
    },
    async removeSocialLink(param: SocialLink) {
      const { code, data, msg } = await api.delete<
        any,
        IResponse<SocialLink[]>
      >(`/my/sociallinks?id=${param.id}`);
      if (code === 200) {
        this.socialLinks = plainToInstance(SocialLink, data);
      } else {
        throw new Error(msg);
      }
    },
    async putSocialLink(param: SocialLink) {
      const { code, data, msg } = await api.put<any, IResponse<SocialLink[]>>(
        '/my/sociallinks?id=${param.id}',
        param
      );
      if (code === 200) {
        this.socialLinks = plainToInstance(SocialLink, data);
      } else {
        throw new Error(msg);
      }
    },
    async getMessages() {
      const { code, data, msg } = await api.get<any, IResponse<any>>(
        '/my/messages'
      );
      if (code === 200) {
        if (data instanceof Array) {
          this.messages = plainToInstance(Message, data);
        } else {
          this.messages = plainToInstance(
            Message,
            data.messages as Array<Message>
          );
        }
      } else {
        throw new Error(msg);
      }
    },
    async setUserInfo(info: any) {
      const { code, data, msg } = await api.post<any, IResponse<Me>>(
        '/me/info',
        info
      );
      if (code === 200) {
        this.currentUser = plainToInstance(Me, data);
      } else {
        throw new Error(msg);
      }
    },
  },
});
